package com.wave.system.thread;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.serotonin.modbus4j.code.DataType;
import com.wave.common.enums.PathPointEnum;
import com.wave.common.utils.redis.RedisUtils;
import com.wave.common.utils.spring.SpringUtils;
import com.wave.system.domain.*;
import com.wave.system.mapper.*;
import com.wave.system.service.ISysNgRecordService;
import com.wave.system.service.ISysProduceArrangeService;
import com.wave.system.util.Modbus4jUtils;
import com.wave.system.util.QRScannerUtil;
import com.wave.system.util.SnCodeConvertUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Component
@Slf4j
public class B1SV1AllowScanCodeListenerThread implements Runnable {

    private SysDeviceSettingMapper sysDeviceSettingMapper = SpringUtils.getBean(SysDeviceSettingMapper.class);

    private SysAlarmRecordMapper sysAlarmRecordMapper = SpringUtils.getBean(SysAlarmRecordMapper.class);

    private SysToolBoardTaskMapper sysToolBoardTaskMapper = SpringUtils.getBean(SysToolBoardTaskMapper.class);

    private SysProductQueryMapper sysProductQueryMapper = SpringUtils.getBean(SysProductQueryMapper.class);

    private SysSettingMapper sysSettingMapper = SpringUtils.getBean(SysSettingMapper.class);

    private ISysProduceArrangeService produceArrangeService = SpringUtils.getBean(ISysProduceArrangeService.class);

    private ISysNgRecordService sysNgRecordService = SpringUtils.getBean(ISysNgRecordService.class);

    private SysProduceRecordMapper sysProduceRecordMapper = SpringUtils.getBean(SysProduceRecordMapper.class);

    /**
     * B1_SV1允许扫码监听
     */
    @Override
    public void run() {
        while (true) {
            try {
                boolean allowScan = Modbus4jUtils.readCoilStatus(1, 4808);
                if (allowScan) {
                    SysDeviceSetting sysDeviceSetting = sysDeviceSettingMapper.selectOne(Wrappers.emptyWrapper());
                    if (ObjectUtil.isEmpty(sysDeviceSetting)) {
                        log.error("B1_SV1允许扫码监听,未配置设备信息");
                        continue;
                    }
                    String toolBoardIp = sysDeviceSetting.getToolBoardIp();
                    //读取扫码枪读到的sn码数据
                    String snCode = QRScannerUtil.getQrCode(toolBoardIp);
                    log.info("B1_SV1获取物料码snCode:{}", snCode);

                    //判断sn码数据是否为空,如果为空，就先在缓存里获取
                    if (RedisUtils.getCacheObject("sncodecache")!=null) {
                        snCode = RedisUtils.getCacheObject("sncodecache");//手动设置的
                        //删除手动设置的sn码
                        RedisUtils.deleteObject("sncodecache");
                    }
                    //判断sn码数据是否为空
                    if (StringUtils.isEmpty(snCode)) {
                        log.error("B1_SV1读码器读到的sn码数据为空");
                        Modbus4jUtils.writeCoil(1, 4009, true);
                        //插入报警记录
                        SysAlarmRecord alarmRecord = new SysAlarmRecord();
                        alarmRecord.setAlarmTime(new Date());
                        alarmRecord.setAlarmType(1);
                        alarmRecord.setAlarmContent("B1_SV1读取产品SN码失败");
                        sysAlarmRecordMapper.insert(alarmRecord);
                        TimeUnit.MILLISECONDS.sleep(100);
                        continue;
                    }

                    //通知PLC扫码成功同时发送读取到的sn码给PLC
                    log.info("通知PLC物料:{}扫码成功", snCode);
                    Modbus4jUtils.writeCoil(1, 4008, true);
                    short[] snCodeData = Modbus4jUtils.setString(snCode);
                    log.info("发送物料码snCode:{}给PLC", snCode);
                    Modbus4jUtils.writeRegisters(1, 0, snCodeData);
                    log.info("通知PLC物料SN码:{}发送成功", snCode);
                    Modbus4jUtils.writeCoil(1, 4184, true);

                    //创建工装板任务和产品查询信息
                    SysToolBoardTask sysToolBoardTask = sysToolBoardTaskMapper.selectOne(Wrappers.lambdaQuery(SysToolBoardTask.class)
                        .eq(SysToolBoardTask::getProductSn, snCode));
                    if (ObjectUtil.isNotEmpty(sysToolBoardTask)) {
                        sysToolBoardTaskMapper.deleteById(sysToolBoardTask);
                    }
                    SysToolBoardTask toolBoardTask = new SysToolBoardTask();
                    toolBoardTask.setProductSn(snCode);
                    toolBoardTask.setPathPoint1("0");
                    toolBoardTask.setPathPoint2("0");
                    toolBoardTask.setPathPoint3("0");
                    toolBoardTask.setTaskStatus("刚创建");
                    sysToolBoardTaskMapper.insert(toolBoardTask);

                    SysProductQuery sysProductQuery = sysProductQueryMapper.selectOne(Wrappers.lambdaQuery(SysProductQuery.class)
                        .eq(SysProductQuery::getProductSn, snCode));
                    if (ObjectUtil.isNotEmpty(sysProductQuery)) {
                        sysProductQuery.setProductSn(snCode + "@1");
                        sysProductQueryMapper.updateById(sysProductQuery);
                    }
                    SysProductQuery query = new SysProductQuery();
                    query.setProductSn(snCode);
                    sysProductQueryMapper.insert(query);

                    //查询sn码是否重码
                    SysProduceRecord record = sysProduceRecordMapper.selectOne(Wrappers.lambdaQuery(SysProduceRecord.class).eq(SysProduceRecord::getProductNumber, snCode));
                    if (ObjectUtil.isNotEmpty(record)) {
                        log.error("物料码:{}重复", snCode);
                        LambdaUpdateWrapper<SysToolBoardTask> updateWrapper = Wrappers.lambdaUpdate(SysToolBoardTask.class)
                            .set(SysToolBoardTask::getTaskStatus, "SN码重码").eq(SysToolBoardTask::getProductSn, snCode);
                        sysToolBoardTaskMapper.update(updateWrapper);
                        // 通知PLC 物料码重复
                        Modbus4jUtils.writeCoil(1, 4025, true);
                        TimeUnit.MILLISECONDS.sleep(500);
                        continue;
                    }
                    String respData = produceArrangeService.checkPackInfoBySnCode(snCode);
                    List<SysProduceArrange> list = produceArrangeService.matchArrangeBySnCodeVersion(snCode, respData);
                    //  if (StringUtils.isEmpty(respData) || CollectionUtils.isEmpty(list)) {
                    if (CollectionUtils.isEmpty(list)) {
                        //log.error("物料码:{}调用mes获取芯片版本信息失败或匹配生产排布失败", snCode);
                        log.error("物料码:{}匹配生产排布失败", snCode);
                        LambdaUpdateWrapper<SysToolBoardTask> updateWrapper = Wrappers.lambdaUpdate(SysToolBoardTask.class)
                            .set(SysToolBoardTask::getTaskStatus, "未分配产线").eq(SysToolBoardTask::getProductSn, snCode);
                        sysToolBoardTaskMapper.update(updateWrapper);
                        // 通知PLC 匹配失败
                        Modbus4jUtils.writeCoil(1, 4025, true);
                        TimeUnit.MILLISECONDS.sleep(500);
                        continue;
                    }
                    Modbus4jUtils.writeCoil(1, 4024, true);
                    log.info("物料码:{}通知PLC型号匹配成功", snCode);

                    SysSetting sysSetting = sysSettingMapper.selectOne(Wrappers.emptyWrapper());
                    if (ObjectUtil.isEmpty(sysSetting)) {
                        log.error("B1_SV1允许扫码监听异常,上位机未设置系统配置");
                        continue;
                    }
                    //如果配置的人工设置，则根据生产排布获取缓存位
                    Integer cacheBit = null;
                    if (sysSetting.getProduceSetting() == 0) {
                        cacheBit = produceArrangeService.getCacheBitByProduceArrange(list);
                    } else {
                        // 如果配置的自动调度，则需要自动进行分配
                        String productCode = SnCodeConvertUtil.getProductCodeBySnCode(snCode) + respData;
                        cacheBit = produceArrangeService.getCacheBitByAutoDispatch(productCode);
                    }
                    if (ObjectUtil.isNull(cacheBit)) {
                        log.error("B1_SV1允许扫码监听异常,获取物料出口位失败");
                        sysNgRecordService.saveNgAndAlarmRecord(snCode, "获取出口号失败");
                        TimeUnit.MILLISECONDS.sleep(100);
                        continue;
                    }
                    //更新工装板任务点位信息
                    sysToolBoardTask = sysToolBoardTaskMapper.selectOne(Wrappers.lambdaQuery(SysToolBoardTask.class)
                        .eq(SysToolBoardTask::getProductSn, snCode));
                    if (!ObjectUtil.isEmpty(sysToolBoardTask)) {
                        sysToolBoardTask.setTargetExport(String.valueOf(PathPointEnum.getPathPoint(cacheBit).getPathPoint()));
                        sysToolBoardTaskMapper.updateById(sysToolBoardTask);
                    }
                    // 发送工装板任务出口号
                    log.info("发送物料出口号给PLC,物料码：{},出口号：{}", snCode, cacheBit);
                    Modbus4jUtils.writeHoldingRegister(1, 12, cacheBit, DataType.TWO_BYTE_INT_SIGNED);
                }

                TimeUnit.MILLISECONDS.sleep(200);
            } catch (Exception e) {
                log.error("B1_SV1允许扫码监听异常", e);
            }
        }
    }
}
